var app = getApp();
const formatTime = date => {
  const year = date.getFullYear()
  const month = date.getMonth() + 1
  const day = date.getDate()
  const hour = date.getHours()
  const minute = date.getMinutes()
  const second = date.getSeconds()

  return year.toString() + '/' + formatNumber(month) + '/' + formatNumber(day) + ' ' + formatNumber(hour) + ':' + formatNumber(minute) + ':' + formatNumber(second);
}

function formatNumber(nn) {
  if (nn < 10) {
    return '0' + nn.toString();
  }
  else {
    return nn.toString();
  }
}

function cmsGetCheckSum(buffer) {
  console.log(buffer)
  var sum = 0;
  for (var i = 0; i < buffer.length - 1; ++i) {
    sum += buffer[i];
  }
  console.log(sum)
  return (sum & 0x7F);
}

var _connected = false;
var _deviceId = '';
var _connect_params = null;
var _disconnect_params = null;
var _notifyServiceId;
var _notifyCharacteristicId;
var _writeServiceId;
var _writeCharacteristicId;
var _dataBuffer;
var _nums = '';

function connect(params) {
  // if (_connected) {
  //   return;
  // }

  _deviceId = params.deviceId;
  _connect_params = params;

  wx.createBLEConnection({
    deviceId: _deviceId,
    success: function(res) {
      console.log(res)
      //_connected: true;

      // if (_connect_callback) {
      //   _connect_callback({success:1, result:res});
      // }

      getThisDeviceServices();
    },
    fail: params.fail
  })
}

// 获取连接设备的service服务
function getThisDeviceServices() {
  console.log('_deviceId:', _deviceId)
  wx.getBLEDeviceServices({
    deviceId: _deviceId,
    success: function(res) {
      console.log(res)
      for (var i = 0; i < res.services.length; ++i) {
        if (res.services[i].uuid.indexOf('FF12') >= 0) {
          _notifyServiceId = res.services[i].uuid;
          _writeServiceId = res.services[i].uuid;
          getThisDeviceNotifyCharacteristic();
          return;
        }
      }
      if (_connect_params.fail) {
        _connect_params.fail(res);
      }
    },
    fail: _connect_params.fail
  })
}

// 获取连接设备的Notify Characteristic UUID
function getThisDeviceNotifyCharacteristic() {
  wx.getBLEDeviceCharacteristics({
    deviceId: _deviceId,
    serviceId: _notifyServiceId,
    success: function(res) {
      console.log(res)
      for (var i = 0; i < res.characteristics.length; i++) {
        if ((res.characteristics[i].properties.notify) && (res.characteristics[i].uuid.indexOf('FF02') >= 0)) {
          _notifyCharacteristicId = res.characteristics[i].uuid;

          listenNotifyCharacteristic();
          return;
        }
      }
      if (_connect_params.fail) {
        _connect_params.fail(res);
      }
    },
    fail: _connect_params.fail
  })
}

// 订阅Notify
function listenNotifyCharacteristic() {
  wx.notifyBLECharacteristicValueChange({
    state: true,
    deviceId: _deviceId,
    serviceId: _notifyServiceId,
    characteristicId: _notifyCharacteristicId,
    success: function(res) {
      console.log(res)
      getThisDeviceWriteCharacteristic();
    },
    fail: _connect_params.fail
  })
}

// 获取连接设备的Write Characteristic UUID
function getThisDeviceWriteCharacteristic() {
  wx.getBLEDeviceCharacteristics({
    deviceId: _deviceId,
    serviceId: _writeServiceId,
    success: function(res) {
      console.log(res)
      for (var i = 0; i < res.characteristics.length; i++) {
        if ((res.characteristics[i].properties.write) && (res.characteristics[i].uuid.indexOf('FF01') >= 0)) {
          _writeCharacteristicId = res.characteristics[i].uuid;
          _connected = true;
          _dataBuffer = new Array();

          wx.onBLECharacteristicValueChange(receiveValues);

          if (_connect_params.success) {
            _connect_params.success(res);
          }

          return;
        }
      }
      if (_connect_params.fail) {
        _connect_params.fail(res);
      }
    },
    fail: _connect_params.fail
  })
}

function disconnect(params) {
  _disconnect_params = params;

  wx.closeBLEConnection({
    deviceId: _deviceId,
    success: function(res) {
      console.log(res);
      _connected: false;

      if (_disconnect_params.success) {
        _disconnect_params.success(res);
      }
    },
    fail: _disconnect_params.fail
  })
}

//发送
function sendToThisDevice(arr, callback_params) {
  console.log(arr);
  var num = parseInt((arr[0] + arr[1] + arr[2] + _nums) / 3)
  console.log(num)
  app.util.request({
    'url':"entry/wxapp/index.add_shebei",
    data:{
      openid:wx.getStorageSync('openid'),
      value:num,
      j_id:wx.getStorageSync('j_id'),
      type:"heart"
    },
    success:function(res)
    {
      wx.showModal({
        cancelColor: '提示',
        content:'测量成功，您的心率为'+num+'次/分钟',
        showCancel:false,
        success:function(con)
        {
          wx.navigateTo({
            url: '/hyb_yl/pharmacy/pages/heartrate/heartrate?j_id='+wx.getStorageSync('j_id')+'&openid='+wx.getStorageSync('openid'),
          })
        }
      })
    }
  })
  var buf = new ArrayBuffer(arr.length)
  var dataView = new DataView(buf)

  for (var i = 0; i < arr.length; i++) {
    dataView.setInt8(i, arr[i]);
  }
  
  wx.writeBLECharacteristicValue({
    deviceId: _deviceId,
    serviceId: _writeServiceId,
    characteristicId: _writeCharacteristicId,
    value: buf,
    success: callback_params.success,
    fail: callback_params.fail
  })
}

// 从Notify特征值收取数据，放入待处理缓冲区，并调用处理流程
function receiveValues(chararacteristic) {
  var u8values = new Uint8Array(chararacteristic.value);
  console.log(u8values)
  for (var i = 0; i < u8values.length; ++i) {
    _dataBuffer.push(u8values[i]);
  }
  console.log(_dataBuffer)
  processBuffer();
}
function buf2hex(buffer) { // buffer is an ArrayBuffer
  return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join(' ');
}
function processBuffer() {
  var last_data = _dataBuffer;
  console.log(_dataBuffer)
//  console.log(buf2hex(last_data));

  while (last_data.length > 0) {
    if (!isPackageHeader(last_data[0])) // 跳过非包头字节
    {
      last_data.shift(); // 删除数组第一个字节
      continue;
    }

    if (last_data[0] == 0xF3) // 对时结果包
    {
      if (last_data.length >= 3) {
        var buffer = last_data.slice(0, 3);
        if (hasPackageHeader(buffer)) {
          // 包内部字节发现包头，跳过此错误包，寻找下一包头
          last_data.shift();
          continue;
        }
        last_data.splice(0, 3);

        unpackSetTime(buffer); // 对时返回值
      } else {
        // 数据不够包长，跳出while，等待下次处理
        break;
      }
    } 
    else if (last_data[0] == 0xE0) // 空间信息包
    {
      if (last_data.length >= 7) {
        var buffer = last_data.slice(0, 7);

        if (hasPackageHeader(buffer)) {
          // 包内部字节发现包头，跳过此错误包，寻找下一包头
          last_data.shift();
          continue;
        }
        last_data.splice(0, 7);

        var ret = unpackSingleDataCapacity(buffer); // 检查空间信息

        if (ret.TYPE == QUERY_SINGLE_DATA_CAPACITY_ECG) {   // 心电数据
          _callbacks_getSingleECG.unupload = ret.UNUPLOAD;
          
            _nums = ret.UNUPLOAD
            console.log(_nums)
          console.log('ecg:', ret.UNUPLOAD)
          if (ret.UNUPLOAD > 0) { // 存在未上传数据
            _callbacks_getSingleECG.uploaded = 0;
            sendToThisDevice(getSingleDataECGInfo(0), {
              success: _callbacks_getSingleECG.success,
              fail: _callbacks_getSingleECG.fail
            });
          } else {
            if (_callbacks_getSingleECG.op_success) {
              _callbacks_getSingleECG.op_success({
                count: 0
              });
            }
          }
        }
      } else {
        // 数据不够包长，跳出while，等待下次处理
        break;
      }
    } 
    else if (last_data[0] == 0xE5) // 心电信息数据包
    {
      if (last_data.length >= 18) {
        var data = last_data.slice(0, 18);
        var info = unpackSingleDataECGInfo(data, _callbacks_getSingleECG.uploaded);
        if (info){
          // 保存信息
          _callbacks_getSingleECG.data.push(info);

          if (_callbacks_getSingleECG.op_process) {
            _callbacks_getSingleECG.op_process({
              case_total: _callbacks_getSingleECG.unupload,
              case_current: _callbacks_getSingleECG.uploaded,
              data_current: _callbacks_getSingleECG.data[_callbacks_getSingleECG.uploaded].ECG.length,
              data_total: _callbacks_getSingleECG.data[_callbacks_getSingleECG.uploaded].LENGTH
            });
          }

          // 开始接收心电图数据
          sendToThisDevice(getSingleDataECGData(0), {
               success: _callbacks_getSingleECG.success,
               fail: _callbacks_getSingleECG.fail
             });
        }
        else{
          // sendToThisDevice(getSingleDataECGInfo(1), {
          //   success: _callbacks_getSingleECG.success,
          //   fail: _callbacks_getSingleECG.fail
          // });
        }
        
        last_data.splice(0, 18);
      } else {
        // 数据不够包长，跳出while，等待下次处理
        break;
      }
    } 
    else if (last_data[0] == 0xE6) // 心电数据包
    {
      var need_packages = Math.ceil((_callbacks_getSingleECG.data[_callbacks_getSingleECG.uploaded].LENGTH - _callbacks_getSingleECG.data[_callbacks_getSingleECG.uploaded].ECG.length) / 6);
      var packs_len = (need_packages >= 10) ? (10 * 17) : (need_packages * 17);

      if (last_data.length >= packs_len) {    // 收到一组心电数据（十包）
        var data = last_data.slice(0, packs_len);
        var ecg_array = new Array();
        var no_error = true;
        for (var i = 0; i < data.length / 17; ++i) {
          var buffer = data.slice(i * 17, (i + 1) * 17);
          var data_length = _callbacks_getSingleECG.data[_callbacks_getSingleECG.uploaded].LENGTH - _callbacks_getSingleECG.data[_callbacks_getSingleECG.uploaded].ECG.length - ecg_array.length;
          data_length = (data_length > 6)? 6: data_length;

          var ret = unpackSingleDataECGData(buffer, data_length); // 6个心电数据

          if (ret == null) {
            no_error = false;
            break;
          }

          for (var j=0; j<ret.length; ++j){
            ecg_array.push(ret[j]);
          }
        }

        if (no_error) //这包数据解析都正确
        {
          for (var i = 0; i < ecg_array.length; ++i) {
            _callbacks_getSingleECG.data[_callbacks_getSingleECG.uploaded].ECG.push(ecg_array[i])
          }

          if (_callbacks_getSingleECG.op_process) {
            _callbacks_getSingleECG.op_process({
              case_total: _callbacks_getSingleECG.unupload,
              case_current: _callbacks_getSingleECG.uploaded,
              data_current: _callbacks_getSingleECG.data[_callbacks_getSingleECG.uploaded].ECG.length,
              data_total: _callbacks_getSingleECG.data[_callbacks_getSingleECG.uploaded].LENGTH
            });
          }

          if (ret.TERMINAL || (_callbacks_getSingleECG.data[_callbacks_getSingleECG.uploaded].ECG.length == _callbacks_getSingleECG.data[_callbacks_getSingleECG.uploaded].LENGTH)) {
            // 此条数据为所有数据的最后一条
            // sendToThisDevice(getSingleDataECGData(126), {
            //   success: _callbacks_getSingleECG.success,
            //   fail: _callbacks_getSingleECG.fail
            // }); //接收完毕

            _callbacks_getSingleECG.uploaded += 1;

            if (_callbacks_getSingleECG.unupload == _callbacks_getSingleECG.uploaded) { //所有心电病例都接收完成
              if (_callbacks_getSingleECG.op_success) {
                _callbacks_getSingleECG.op_success({
                  count: _callbacks_getSingleECG.data.length,
                  data: _callbacks_getSingleECG.data
                });
              }
            }
            else {  // 获取下一条信息和数据
              sendToThisDevice(getSingleDataECGInfo(1), {
                success: _callbacks_getSingleECG.success,
                fail: _callbacks_getSingleECG.fail
              });
            } 
          } else {
            // 设备中还有数据
            sendToThisDevice(getSingleDataECGData(1), {
              success: _callbacks_getSingleECG.success,
              fail: _callbacks_getSingleECG.fail
            }); //接收完毕，继续接收下一组未上传数据
          }
        } else {
          // 丢弃此包收到的所有数据，并请求设备重发
          sendToThisDevice(getSingleDataECGData(2), {
            success: _callbacks_getSingleECG.success,
            fail: _callbacks_getSingleECG.fail
          }); //接收未成功，要求设备重发本次数据
        }
        last_data.splice(0, packs_len);
      } else {
        // 数据不够包长，跳出while，等待下次处理
        break;
      }
    } 
    else {
      // 删除不处理的包头，则包体部分在下次循环时被过滤
      last_data.shift();
    }
  }

  _dataBuffer = last_data;
}

function hasPackageHeader(buffer) {
  for (var i = 1; i < buffer.length; ++i) {
    if (buffer[i] & 0x80) {
      return true;
    }
  }

  return false;
}

function isPackageHeader(byte) {
  return ((byte & 0x80) != 0);
}

function queryVersion() {
  var buffer = new Array(2);
  console.log(buffer)
  buffer[0] = 0x82;
  buffer[1] = cmsGetCheckSum(buffer);

  return buffer;
}

var _callbacks_setTime = {
  op_success: null,
  op_fail: null,
  success: null,
  fail: null
};

function setTime(callbacks_settime) {
  console.log(callbacks_settime)
  _callbacks_setTime = callbacks_settime;

  var now = new Date();
  var buffer = new Array(10);

  buffer[0] = 0x83;
  buffer[1] = now.getFullYear() - 2000;
  buffer[2] = now.getMonth() + 1;
  buffer[3] = now.getDate();
  buffer[4] = now.getHours();
  buffer[5] = now.getMinutes();
  buffer[6] = now.getSeconds();
  buffer[7] = 0;
  buffer[8] = 0;
  buffer[9] = cmsGetCheckSum(buffer);
console.log(buffer)
  sendToThisDevice(buffer, {
    success: _callbacks_setTime.success,
    fail: _callbacks_setTime.fail
  });
}

function unpackSetTime(buffer, callback) {
  console.log(buffer)
  console.log(callback)
  if ((buffer.length != 3) || (buffer[0] != 0xF3) || (buffer[2] != cmsGetCheckSum(buffer))) {
    if (_callbacks_setTime.op_fail) {
      _callbacks_setTime.op_fail(false);
    }
    return false;
  }

  if (buffer[1] == 0) {
    if (_callbacks_setTime.op_success) {
      _callbacks_setTime.op_success(true);
    }
  } else {
    if (_callbacks_setTime.op_fail) {
      _callbacks_setTime.op_fail(false);
    }
  }
}

function queryPower() {
  var buffer = new Array(2);
  console.log(buffer);
  buffer[0] = 0x86;
  buffer[1] = cmsGetCheckSum(buffer);
  console.log(buffer);
  return buffer;
}

const QUERY_SINGLE_DATA_CAPACITY_SPO2 = 0;
const QUERY_SINGLE_DATA_CAPACITY_STEPS = 1;
const QUERY_SINGLE_DATA_CAPACITY_ECG = 3;

function querySingleDataCapacity(datatype) {
  console.log(datatype)
  var buffer = new Array(3);

  buffer[0] = 0x90;
  buffer[1] = datatype;
  buffer[2] = cmsGetCheckSum(buffer);
  console.log(buffer)
  return buffer;
}

function unpackSingleDataCapacity(buffer) {
  if ((buffer.length != 7) || (buffer[0] != 0xE0) || (buffer[6] != cmsGetCheckSum(buffer))) {
    return null;
  }

  var total = buffer[3] * 128 + buffer[2];
  var unupload = buffer[5] * 128 + buffer[4];

  return {
    TYPE: buffer[1],
    TOTAL: total,
    UNUPLOAD: unupload
  };
}

var _callbacks_getSingleSpo2 = {
  op_success: null,
  op_fail: null,
  success: null,
  fail: null,
  count: 0,
  data: null
};

function getSingleSpo2(callbacks) {
  _callbacks_getSingleSpo2 = callbacks;
  _callbacks_getSingleSpo2.unupload = 0;
  _callbacks_getSingleSpo2.uploaded = 0;
  _callbacks_getSingleSpo2.count = 0;
  _callbacks_getSingleSpo2.data = new Array();

  sendToThisDevice(querySingleDataCapacity(QUERY_SINGLE_DATA_CAPACITY_SPO2), {
    success: null,
    fail: _callbacks_getSingleSpo2.fail
  });
}

const SINGLE_DATA_SPO2_ACK_LENGTH = 11;

function getSingleDataSpo2(datatype) {
  var buffer = new Array(3);

  buffer[0] = 0x91;
  buffer[1] = datatype;
  buffer[2] = cmsGetCheckSum(buffer);

  return buffer;
}

function unpackSingleDataSpo2(buffer) {
  if ((buffer.length != 11) || (buffer[0] != 0xE1) || (buffer[10] != cmsGetCheckSum(buffer))) {
    return null;
  }

  if (buffer[3] & 0x40) {
    buffer[9] |= 0x80;
    buffer[3] = buffer[3] & 0x0F;
  }

  var packno = buffer[1] & 0x0F;
  var terminal = false;
  if (buffer[1] & 0x40) {
    terminal = true;
  }

  console.log(buffer[2])

  var time = formatTime(new Date(buffer[1] + 2000, buffer[2] - 1, buffer[3], buffer[4], buffer[5], buffer[6]));

  var spo2 = buffer[8];
  var pr = buffer[9];

  return {
    PACKNO: packno,
    TERMINAL: terminal,
    TIME: time,
    SPO2: spo2,
    PR: pr
  };
}

var _callbacks_getSingleSteps = {
  op_success: null,
  op_fail: null,
  success: null,
  fail: null,
  count: 0,
  data: null
};

function getSingleSteps(callbacks) {
  _callbacks_getSingleSteps = callbacks;
  _callbacks_getSingleSteps.unupload = 0;
  _callbacks_getSingleSteps.uploaded = 0;
  _callbacks_getSingleSteps.count = 0;
  _callbacks_getSingleSteps.data = new Array();

  sendToThisDevice(querySingleDataCapacity(QUERY_SINGLE_DATA_CAPACITY_STEPS), {
    success: null,
    fail: _callbacks_getSingleSteps.fail
  });
}

function getSingleDataSteps(datatype) {
  var buffer = new Array(3);

  buffer[0] = 0x92;
  buffer[1] = datatype;
  buffer[2] = cmsGetCheckSum(buffer);

  return buffer;
}

function unpackSingleDataSteps(buffer) {
  if ((buffer.length == 11) && ((buffer[0] != 0xE2) || (buffer[10] != cmsGetCheckSum(buffer)))) {
    return null;
  }

  if ((buffer.length == 13) && ((buffer[0] != 0xEA) || (buffer[12] != cmsGetCheckSum(buffer)))) {
    return null;
  }

  var packno = buffer[1] & 0x0F;
  var terminal = false;
  if (buffer[1] & 0x40) {
    terminal = true;
  }

  var year = buffer[2] + 2000;
  var month = buffer[3];
  var day = buffer[4];

  buffer[6] |= (buffer[5] & 0x01) << 7;
  buffer[7] |= (buffer[5] & 0x02) << 6;
  buffer[8] |= (buffer[5] & 0x04) << 5;
  buffer[9] |= (buffer[5] & 0x08) << 4;
  if (buffer.length == 13){
    buffer[10] |= (buffer[5] & 0x10) << 3;
    buffer[11] |= (buffer[5] & 0x20) << 2;
  }

  var cal = buffer[7] * 256 + buffer[6];
  var steps = buffer[9] * 256 + buffer[8];
  var target = 0;
  if (buffer.length == 13){
    target = buffer[11] * 256 + buffer[10];
  }

  return {
    PACKNO: packno,
    TERMINAL: terminal,
    TIME: [year, month, day].map(formatNumber).join('/'),
    STEPS: steps,
    CAL: cal,
    TARGET: target
  };
}

var _callbacks_getSingleECG = {
  op_success: null,
  op_fail: null,
  success: null,
  fail: null,
  count: 0,
  data: null
};

function getSingleECG(callbacks) {
  console.log(callbacks)
  _callbacks_getSingleECG = callbacks;
  _callbacks_getSingleECG.unupload = 0;
  _callbacks_getSingleECG.uploaded = 0;
  _callbacks_getSingleECG.count = 0;
  _callbacks_getSingleECG.data = new Array();

  sendToThisDevice(querySingleDataCapacity(QUERY_SINGLE_DATA_CAPACITY_ECG), {
    success: null,
    fail: _callbacks_getSingleECG.fail
  });
}

function getSingleDataECGInfo(datatype) {
  console.log(datatype)
  var buffer = new Array(3);

  buffer[0] = 0x95;
  buffer[1] = datatype;
  buffer[2] = cmsGetCheckSum(buffer);

  return buffer;
}

function getSingleDataECGData(datatype) {
  var buffer = new Array(3);

  buffer[0] = 0x96;
  buffer[1] = datatype;
  buffer[2] = cmsGetCheckSum(buffer);
  console.log(datatype)
  console.log(buffer)
  return buffer;
}

function unpackSingleDataECGInfo(buffer, index) {
  console.log(buffer);
  console.log(index)
  if ((buffer.length != 18) || (buffer[0] != 0xE5) || (buffer[17] != cmsGetCheckSum(buffer))) {
    return null;
  }

  var time = formatTime(new Date(buffer[1] + 2000, buffer[2] - 1, buffer[3], buffer[4], buffer[5], buffer[6]));

  var hr = buffer[8] * 128 + buffer[7];
  var diagnose = new Array();
  diagnose[0] = buffer[9];
  diagnose[1] = buffer[10];
  diagnose[2] = buffer[11];
  diagnose[3] = buffer[12];
  diagnose[4] = buffer[13];
  diagnose[5] = buffer[14];
  console.log(diagnose)
  var length = buffer[16] * 128 + buffer[15];

  return {
    INDEX: index,
    TIME: time,
    HR: hr,
    DIAGNOSE: diagnose,
    LENGTH: length,
    ECG: new Array()
  };
}

function unpackSingleDataECGData(buffer, length) {
  if ((buffer.length != 17) || (buffer[0] != 0xE6) || (buffer[16] != cmsGetCheckSum(buffer))) {
    return null;
  }

  var packno = buffer[1] & 0x0F;
  var terminal = false;
  if (buffer[1] & 0x40) {
    terminal = true;
  }

  buffer[4] |= (buffer[2] & 0x01) << 7;
  buffer[5] |= (buffer[2] & 0x02) << 6;
  buffer[6] |= (buffer[2] & 0x04) << 5;
  buffer[7] |= (buffer[2] & 0x08) << 4;
  buffer[8] |= (buffer[2] & 0x10) << 3;
  buffer[9] |= (buffer[2] & 0x20) << 2;
  buffer[10] |= (buffer[2] & 0x40) << 1;

  buffer[11] |= (buffer[3] & 0x01) << 7;
  buffer[12] |= (buffer[3] & 0x02) << 6;
  buffer[13] |= (buffer[3] & 0x04) << 5;
  buffer[14] |= (buffer[3] & 0x08) << 4;
  buffer[15] |= (buffer[3] & 0x10) << 3;

  var temp = new Array(6);

  temp[0] = buffer[5] * 256 + buffer[4];
  temp[1] = buffer[7] * 256 + buffer[6];
  temp[2] = buffer[9] * 256 + buffer[8];
  temp[3] = buffer[11] * 256 + buffer[10];
  temp[4] = buffer[13] * 256 + buffer[12];
  temp[5] = buffer[15] * 256 + buffer[14];

  var data = new Array();

  for (var i=0; i<length; ++i) {
    data.push(temp[i]);
  }
  console.log(data);
  return data;
}

module.exports = {
  connect: connect,
  disconnect: disconnect,
  setTime: setTime,
  getSingleSpo2: getSingleSpo2,
  getSingleSteps: getSingleSteps,
  getSingleECG: getSingleECG,
}